package hydrap2p.servicemanager.listen;

import hydrap2p.ServiceLocation;

import java.util.LinkedList;
import java.util.List;

public class ListenerQueue implements Listener {

	private boolean running;
	private Listener listener;
	private List<ListenerEvent> queue;
	private Thread pusher;
	
	public ListenerQueue(Listener listener)
	{
		queue=new LinkedList<ListenerEvent>();
		this.listener=listener;
		running=true;
		
		pusher=new Thread(new QueuePusher());
		pusher.start();
	}
	
	private interface ListenerEvent {
		public void doIt();
	}
	
	private void addSync(ListenerEvent event)
	{
		synchronized(queue)
		{
			queue.add(event);
			queue.notifyAll();
		}
	}
	
	private class QueuePusher implements Runnable
	{

		@Override
		public void run() {
			while (running)
			{
				ListenerEvent event = null;
				synchronized(queue)
				{
					if (queue.size()>0)
					{
						event=queue.remove(0);
					}
				}
				if (event!=null)
				{
					event.doIt();
				}
				else
				{
					try {
						synchronized(queue)
						{
							queue.wait();
						}
					} catch (InterruptedException e) {
						// Signalled to update status or something
					}
				}
				try {
					Thread.sleep(10);	// let other thread finish doing stuff
				} catch (InterruptedException e) {
					
				}	
			}
		}
		
	}

	@Override
	public void newService(final String name, final ServiceLocation location) {
		addSync(new ListenerEvent() {
			public void doIt() {
				try {
					listener.newService(name, location);
				} catch (Exception e) {
					died();
				}
			}			
		});
	}

	@Override
	public void delService(final String name) {
		addSync(new ListenerEvent() {
			public void doIt() {
				try {
					listener.delService(name);
				} catch (Exception e) {
					died();
				}
			}			
		});
	}
	
	@Override
	public void stop() {
		running=false;
		pusher.interrupt();
	}
	
	private void died(){
		// this listener somehow died
		Listeners.delListener(this);
	}

	@Override
	public int hashCode()
	{
		return listener.hashCode();
	}
	
	@Override
	public boolean equals(Object other)
	{
		return listener.equals(other);
	}
	
}
